<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script>
    class Node{//定义数据结构
      constructor(option,children){
        this.option = option//运算符
        this.children = children//运算符左右的变量或算式
      }
      
      //计算结果
      calc(){
        let a
        let b
        if(typeof this.children[0] ==='number'){//计算运算符左边的结果
          a = this.children[0]
        }else{
          a = this.children[0].calc()
        }

        if(typeof this.children[1] === 'number'){//计算运算符右边的结果
          b = this.children[1]
        }else{
          b = this.children[1].calc()
        }

        switch (this.option){//判断运算符 返回计算结果
          case '+':
           return a+b
          case '-':
           return a-b
          case '*':
           return a*b
          case '/':
            if(b === 0){
              throw '除数不能为0'
            }
           return a/b
          default:
           throw '您输入的表达式有误'
        }
      }
     
      toString(){ //在控制台打印数据结构          例如1+2+3打印出来因该是这种结构： +
        let output = ''//存放数据                                                 1
        let r = ''//存放数据的缩进                                                 + 
        put(this,r)   //                                                         2
        function put(item,space){//item：数据  space：上一层递归的空格缩进            3
          output += r
          output+=`${item.option}\n`
          r += '\xa0'

          item.children.forEach(i=>{
            if(typeof i === 'number'){
              output += r
              output += `${i}\n`  
            }else{
            put(i,r)
            //  r = r.substring(0,r.length-1)
            r = (space+='\xa0')
            }
          })
          return output
        }      
        return output
      }
    }

    class Delect{ //处理数据，将传过来的字符串表达式转换为数组
      constructor(expressionn){
        this.symbol = ['+','-','*','/','(',')']
        this.re = /\d/
        this.re2 = /\./
        this.tokens = []//存放处理后的数据
        this.chars = expressionn.trim().split('')//将每个字符分割成一个数组
        console.log(this.chars)
        this.token = ''//存放临时数据       
      }

      dealWith(){
        this.chars.forEach(c=>{//将数组中相邻的数字连接起来，遇到运算符就分割
          if(this.re.test(c) || this.re2.test(c)){//当前元素为数字或（.）时，进行字符串拼接
            this.token += c
          } else if (c == ' ' && token) {//当前元素为空格时将token push 进tokens 并将token清空
            this.tokens.push(this.token)
            this.token = ''
          } else if(this.symbol.includes(c)){//当前元素为一个运算符或括号时，将token push 进 tokens里，并将临时变量token清空
              if(this.token){
                if(this.token.split('.').length-1 >1){//如果当前的token里面有大于一个（.）说明表达式不正确，每个浮点数只能有一个小数点
                  throw '您输入的表达式有误'
                }
                this.tokens.push(this.token)
                this.token = ''
              }
              this.tokens.push(c)
            }
        })
        if (this.token) {
            this.tokens.push(this.token)
            }
            console.log(this.tokens)
            return this.tokens
      }
    }
    let tree = new Node('-',[1,new Node('+',[1,new Node('*',[6,3])])])
    //单元测试
    console.log(tree,tree.calc(),tree.toString())
    console.assert( new Node('-',[1,new Node('+',[1,new Node('*',[6,3])])]).calc() === -18 )
    console.assert(new Node('+',[1,1]).calc() === 2)
    console.assert(new Node('*',[8,new Node('-',[8,5])]).calc()===24)
    console.assert(new Node('+',[new Node('/',[4,2]),3]).calc() === 5)
    console.assert(new Node('*',[new Node('/',[4,2]),new Node('/',[4,2])]).calc() === 4)
    console.assert(new Node('-',[2,new Node('/',[4,2])]).calc() === 0)
    console.assert(new Node('/',[6,3]).calc() === 2)
    console.assert(new Node('+',[new Node('-',[5,3]),new Node('-',[5,new Node('*',[new Node('/',[4,2]),new Node('/',[6,3])])])]).calc() ===3 )
    console.assert(new Node('+',[new Node('-',[5,3]),new Node('-',[5,3])]).calc() === 4)
    console.log(new Node('+',[1,new Node('+',[2,new Node('+',[3,5])])]).toString())
    console.log(new Node('+',[1,new Node('+',[new Node('-',[6,7]),new Node('+',[3,5])])]).toString())
    console.log(new Node('+',[new Node('+',[2,new Node('+',[3,5])]),1]).toString())
    console.log(new Node('+',[new Node('-',[5,3]),new Node('-',[5,new Node('*',[new Node('/',[4,2]),new Node('/',[6,new Node('*',[2,new Node('/',[8,4])])])])])]).toString())   
    // console.log(new Node('/',[4,0]).calc())
    let delect = new Delect('30+5-2+5').dealWith()
    let ccc = /(\d+[+-/*]\d+)/
    console.log(ccc.test('30+5-2+5'))
    //var arr =  ['30','+','5','-','2','+','5']'30 5 + 2 -5 +'
    console.log(new Node('+',[5,new Node('-',[2,new Node('+',[30,5])])]).calc())
    delect.reverse()
    
    //模拟了两个栈 一个用来存储数字，一个用来存储运算符
    class Zhan1{//栈1 用来存储变量
      constructor(){
        this.item =[]//存储变量
      }
      push(element){//往栈顶添加元素
        this.item.push(element)
      }
      pop(){//从栈顶删除元素
        return this.item.pop()
      }
    }
    class Zhan2{//栈2 用来存储表达式
      constructor(){
        this.item =[]
      }
      push(element){
        this.item.push(element)
      }
      pop(){
        return this.item.pop()
      }
    }
    // let zhan1 = new Zhan1()
    // let zhan2 = new Zhan2()
    // delect.forEach((item,index)=>{//往栈里添加数据
    //   if(['+','-','*','/','(',')'].includes(item)){
    //     zhan2.push(item)
    //   }else{
    //     zhan1.push(Math.floor(item))
    //   }
    // })
    // function tr(){//动态构造数据结构，（Node 类）
    //   //每一次构造都会删除栈1的两个元素和栈2的一个元素
    //   if(zhan1.item.length === 2){//当栈1只剩下两个元素时说明已经到了栈底，没有再下一层的元素了，所以直接将最后两个元素添加数据结构，然后推出
    //    return new Node (zhan2.pop(),[zhan1.pop(),zhan1.pop()])
    //   }else{
    //   return new Node(zhan2.pop(),[zhan1.pop(),tr()])
    //   }
    // }
   
    // function constructStack(delect){
    //   let zhan1 = new Zhan1()
    // let zhan2 = new Zhan2()
    // delect.forEach((item,index)=>{//往栈里添加数据
    //   if(['+','-','*','/','(',')'].includes(item)){
    //     zhan2.push(item)
    //   }else{
    //     zhan1.push(Math.floor(item))
    //   }
    // })
    // return tr()
    // function tr(){//动态构造数据结构，（Node 类）
    //   //每一次构造都会删除栈1的两个元素和栈2的一个元素
    //   if(zhan1.item.length === 2){//当栈1只剩下两个元素时说明已经到了栈底，没有再下一层的元素了，所以直接将最后两个元素添加数据结构，然后推出
    //    return new Node (zhan2.pop(),[zhan1.pop(),zhan1.pop()])
    //   }else{
    //   return new Node(zhan2.pop(),[zhan1.pop(),tr()])
    //   }
    // }
    // }
    function constructStack(delect){
      let zhan1 = new Zhan1()
    let zhan2 = new Zhan2()
    delect.forEach((item,index)=>{//往栈里添加数据
      if(['+','-','*','/','(',')'].includes(item)){
        zhan2.push(item)
      }else{
        zhan1.push(Math.floor(item))
      }
    })
    return tr()
    function tr(){//动态构造数据结构，（Node 类）
      //每一次构造都会删除栈1的两个元素和栈2的一个元素
      if(zhan1.item.length === 2){//当栈1只剩下两个元素时说明已经到了栈底，没有再下一层的元素了，所以直接将最后两个元素添加数据结构，然后推出
       return new Node (zhan2.pop(),[zhan1.pop(),zhan1.pop()])
      }else{
      return new Node(zhan2.pop(),[zhan1.pop(),tr()])
      }
    }
    }
    console.log(constructStack(delect).calc(),constructStack(delect))

    // console.log(tr().calc(),tree)
    
    </script>
    
</body>
</html>